<?php

namespace service;

use EasyWeChat\Core\Exceptions\FaultException;
use EasyWeChat\Foundation\Application;
use EasyWeChat\Payment\Order;
use EasyWeChat\Payment\Payment;
use repository\PaymentRepositories\PaymentRepositories;
use util\Hook\Hook;

/**
 * 微信支付 Service
 * Class WechatService
 * @package service
 */
class WechatService
{
    private static $instance = null;

    /**
     * 配置数据
     * @return array
     */
    public static function options()
    {
        $config = [
            'app_id' => '',
            'secret' => '',
            'token' => '',
            'guzzle' => [
                'timeout' => 10.0, // 超时时间（秒）
                'verify' => false
            ],
        ];
        $config['payment'] = [
            'merchant_id' => '',
            'key' => '',
            'cert_path' => '',
            'key_path' => '',
            'notify_url' => 'https://域名/test/notify',
        ];
        return $config;
    }

    /**
     * 应用对象
     * @param false $cache
     * @return Application
     */
    public static function application($cache = false)
    {
        (self::$instance === null || $cache === true) && (self::$instance = new Application(self::options()));
        return self::$instance;
    }

    /**
     * 支付
     * @return Payment
     */
    public static function paymentService()
    {
        return self::application()->payment;
    }

    /**
     * 生成支付订单对象
     * @param $openid
     * @param $out_trade_no
     * @param $total_fee
     * @param $attach
     * @param $body
     * @param string $detail
     * @param string $trade_type
     * @param array $options
     * @return Order
     */
    protected static function paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
    {
        $total_fee = bcmul($total_fee, 100, 0);
        $order = array_merge(compact('out_trade_no', 'total_fee', 'attach', 'body', 'detail', 'trade_type'), $options);
        if (!is_null($openid)) $order['openid'] = $openid;
        if ($order['detail'] == '') unset($order['detail']);
        return new Order($order);
    }

    /**
     * 获得下单ID
     * @param $openid
     * @param $out_trade_no
     * @param $total_fee
     * @param $attach
     * @param $body
     * @param string $detail
     * @param string $trade_type
     * @param array $options
     * @return mixed
     */
    public static function paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
    {
        $order = self::paymentOrder($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options);
        $result = self::paymentService()->prepare($order);
        if ($result->return_code == 'SUCCESS' && $result->result_code == 'SUCCESS') {
            return $result;
        } else {
            if ($result->return_code == 'FAIL') {
                // 抛出异常 ('微信支付错误返回：' . $result->return_msg); TODO
            } else if (isset($result->err_code)) {
                // 抛出异常 ('微信支付错误返回：' . $result->err_code_des); TODO
            } else {
                // 抛出异常 ('没有获取微信支付的预支付ID，请重新发起支付!'); TODO
            }
            exit;
        }
    }

    /**
     * 获得 APP 支付参数
     * @param $out_trade_no
     * @param $total_fee
     * @param $attach
     * @param $body
     * @param string $detail
     * @param string $trade_type
     * @param array $options
     * @return array
     */
    public static function appPay($out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'APP', $options = [])
    {
        $paymentPrepare = self::paymentPrepare(null, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options);
        return self::paymentService()->configForAppPayment($paymentPrepare->prepay_id);
    }

    /**
     * 获得jsSdk支付参数
     * @param $openid
     * @param $out_trade_no
     * @param $total_fee
     * @param $attach
     * @param $body
     * @param string $detail
     * @param string $trade_type
     * @param array $options
     * @return array|string
     */
    public static function jsPay($openid, $out_trade_no, $total_fee, $attach, $body, $detail = '', $trade_type = 'JSAPI', $options = [])
    {
        $paymentPrepare = self::paymentPrepare($openid, $out_trade_no, $total_fee, $attach, $body, $detail, $trade_type, $options);
        return self::paymentService()->configForJSSDKPayment($paymentPrepare->prepay_id);
    }

    /**
     * 微信支付成功回调接口
     * @throws FaultException
     */
    public static function handleNotify()
    {
        self::paymentService()->handleNotify(function ($notify, $successful) {
            if ($successful && isset($notify->out_trade_no)) {
                if (isset($notify->attach) && $notify->attach) {
                    return (new Hook(PaymentRepositories::class, 'wechat'))->listen($notify->attach, $notify->out_trade_no);
                }
                return false;
            }
        });
    }
}